/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Secure Document Class
 *      Provides a password-protected document storage class.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.IO;
using Adaptive.Foundation;
using Adaptive.Foundation.Security;

namespace Adaptive.Foundation.IO
{
    /// <summary>
    /// Provides a password-protected document storage class.
    /// </summary>
    /// <remarks>
    /// This class provides a powerfully-encrypted document storage capability protected
    /// by a text password.
    /// </remarks>
    public class SecureDocument : DisposableObjectBase
    {
		/*--------------------------------------------------------------------------------
		 * Public Event Declarations
		 *------------------------------------------------------------------------------*/
		#region	Public Event Declarations
		/// <summary>
		/// Occurs when a password is required.
		/// </summary>
		public event AuthenticationRequiredEventHandler AuthenticationRequired;
		/// <summary>
		/// Occurs to update the progress of an operation.
		/// </summary>
		public event ProgressEventHandler ProgressUpdate;
		#endregion

        /*--------------------------------------------------------------------------------
		 * Private Constants Declarations
		 *------------------------------------------------------------------------------*/
        #region	Private Constants Declarations
        /// <summary>
		/// Default file name.
		/// </summary>
		private const string DEFAULT_FILENAME = "[Untitled]";

        private const string LOAD_MSG = "Loading...";
		#endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
		/// <summary>
		/// Name of the file.
		/// </summary>
		private string _fileName = DEFAULT_FILENAME;
		/// <summary>
		/// Path in which file is located.
		/// </summary>
		private string _filePath = string.Empty;
		/// <summary>
		/// Password string value.
		/// </summary>
		private UserPassword _password;
		/// <summary>
		/// Text of the document.
		/// </summary>
		private string _textContent = string.Empty;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public SecureDocument()
        {
            _password = new UserPassword();
        }
        /// <summary>
        /// Initializes a new instance of the class for the specified file.
        /// </summary>
        /// <param name="fileName">
        /// The name of the file to be opened.
        /// </param>
        public SecureDocument(string fileName)
        {
            _password = new UserPassword();
            LoadDocument(fileName);
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if ((!Disposed) && (disposing))
            {
                if (_password != null)
                    _password.Dispose();
            }

            _fileName = null;
            _filePath = null;
            _textContent = null;
            _password = null;

            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets the name of the file.
        /// </summary>
        /// <value>
        /// A valid Win32 file name.
        /// </value>
        public string FileName
        {
            get { return _fileName; }
            set { _fileName = value; }
        }
        /// <summary>
        /// Gets or sets the name of the path in which the file is located.
        /// </summary>
        /// <value>
        /// A valid Win32 path name.
        /// </value>
        public string FilePath
        {
            get { return _filePath; }
            set { _filePath = value; }
        }
        /// <summary>
        /// Gets or sets the current content of the file.
        /// </summary>
        /// <value>
        /// Content to be stored.
        /// </value>
        public string Text
        {
            get { return _textContent; }
            set { _textContent = value; }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods / Event Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods / Event Methods
        /// <summary>
        /// Raises the <see cref="AuthenticationRequired"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="AuthenticationRequiredEventArgs"/> event arguments instance
        /// used to transport authentication data.
        /// </param>
        private void OnAuthenticationRequired(AuthenticationRequiredEventArgs e)
        {
            if (AuthenticationRequired != null)
                AuthenticationRequired(this, e);
        }
        /// <summary>
        /// Raises the <see cref="ProgressUpdate"/> event.
        /// </summary>
        /// <param name="e">
        /// A <see cref="ProgressEventArgs"/> event arguments instance 
        /// containing the current status information.
        /// </param>
        private void OnProgressUpdate(ProgressEventArgs e)
        {
            if (ProgressUpdate != null)
                ProgressUpdate(this, e);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Loads the specified file into memory.
        /// </summary>
        /// <param name="pathAndFileName">
        /// The path and name of the file to be loaded.
        /// </param>
        /// <returns>
        /// <b>true </b> if the load is successful; otheriwse, returns <b>false</b>.
        /// </returns>
        public bool LoadDocument(string pathAndFileName)
        {
            _filePath = Path.GetDirectoryName(pathAndFileName);
            _fileName = Path.GetFileName(pathAndFileName);
            return LoadDocument();
        }
        /// <summary>
        /// Loads a secure text file into memory.
        /// </summary>
        /// <returns>
        /// <b>true </b> if the load is successful; otheriwse, returns <b>false</b>.
        /// </returns>
        public bool LoadDocument()
        {
            ProgressEventArgs evArgs = null;		//Event arguments.
            AiSecureFile secureFile = null;         //Secure file to be loaded.
            byte[] key = null;                      //Primary encryption key.
            byte[] iv = null;                       //Primary IV.
            bool returnValue = false;                //Return value.

            //Update the UI.
            evArgs = new ProgressEventArgs();
            evArgs.Status = LOAD_MSG;
            evArgs.PercentComplete = 10;
            OnProgressUpdate(evArgs);

            //Create the keys.
            key = CryptoKeyFactory.PasswordToAesKey(_password.Value);
            iv = CryptoKeyFactory.PasswordToAesIV(_password.Value);

            secureFile = new AiSecureFile(System.IO.Path.Combine(_filePath, _fileName));
            secureFile.Key = key;
            secureFile.IV = iv;

            //Update the UI.
            evArgs = new ProgressEventArgs();
            evArgs.Status = LOAD_MSG;
            evArgs.PercentComplete = 25;
            OnProgressUpdate(evArgs);

            returnValue = secureFile.Load();
            if (returnValue) 
                _textContent = Conversion.ToString(secureFile.DataContent);
            
            secureFile.Dispose();

            return returnValue;

        }
        /// <summary>
        /// Saves the current document with the security password to the specified
        ///  location.
        /// </summary>
        /// <param name="pathAndFileName">
        /// The path and name of the file to be stored.
        /// </param>
        /// <returns>
        /// <b>true </b> if the save is successful; otherwise, <b>false</b>.
        /// </returns>
        public bool SaveDocument(string pathAndFileName)
        {
            _filePath = Path.GetDirectoryName(pathAndFileName);
            _fileName = Path.GetFileName(pathAndFileName);
            return SaveDocument();
        }
        /// <summary>
        /// Saves the current document with the security password to the specified
        ///  location.
        /// </summary>
        /// <returns>
        /// <b>true </b> if the save is successful; otherwise, <b>false</b>.
        /// </returns>
        public bool SaveDocument()
        {
            ProgressEventArgs evArgs = null;		//Event arguments.
            AiSecureFile secureFile = null;         //Secure file to be loaded.
            byte[] key = null;                      //Primary encryption key.
            byte[] iv = null;                       //Primary IV.
            bool returnValue = false;                //Return value.

            //Update the UI.
            evArgs = new ProgressEventArgs();
            evArgs.Status = LOAD_MSG;
            evArgs.PercentComplete = 10;
            OnProgressUpdate(evArgs);

            //Create the keys.
            key = CryptoKeyFactory.PasswordToAesKey(_password.Value);
            iv = CryptoKeyFactory.PasswordToAesIV(_password.Value);

            secureFile = new AiSecureFile(System.IO.Path.Combine(_filePath, _fileName));
            secureFile.Key = key;
            secureFile.IV = iv;

            //Update the UI.
            evArgs = new ProgressEventArgs();
            evArgs.Status = LOAD_MSG;
            evArgs.PercentComplete = 25;
            OnProgressUpdate(evArgs);

            secureFile.DataContent = Conversion.ToBytes(_textContent);
            returnValue = secureFile.Save();
            secureFile.Dispose();

            return returnValue;

        }
        /// <summary>
        /// Sets the current password value used to assign to new files being
        /// saved and to authenticate against files being loaded.
        /// </summary>
        /// <param name="password">
        /// A file-access password value.
        /// </param>
        public void SetPassword(string password)
        {
            //Store in protected memory.
            _password.Value = password;
        }
        #endregion
    }
}
